package portal.action.rest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import portal.beans.Node;
import portal.common.MyStringUtils;
import portal.common.ResultData;
import portal.conf.HostsConf;
import portal.conf.entity.BaseConf;
import portal.conf.entity.HostGroupEntity;
import portal.mybatis.dao.NodeDetail;
import portal.mybatis.dao.service.HostService;
import portal.mybatis.dao.service.VNodeService;
import portal.mybatis.page.Page;
import utils.Log4jInit;

/************************************************************************************
 * @author 徐文远
 * @since  2018-10-08
 * Action 遵循 RestFul 操作规范
 * GET  查询
 * POST 新增/功能操作
 * PUT  全量更新
 * PATCH 部分更新
 * DELETE 删除 
 * **********************************************************************************/
@RestController
public class HostAction  extends BaseAction {
	@Autowired
	HostService hostService;
	@Autowired 
	VNodeService vNodeService;
	@Autowired
	HostsConf hostsConf;
	//@RequestMapping(value="/hostgroup",method=RequestMethod.POST)
	/*@Deprecated
	public void addHostToGroup(NodeEntity node){
		//1、添加到 /etc/hosts
		etcHostsConf.insertConf(node.getHostName(), node.getIp(), node.getDomain());
		//1.1 此处是否需要徐该hosts.conf中的host 信息待确认
		//2、更新Hosts.conf 中的HostGroup ,
		boolean ret=hostGroupConf.updateConf(node.getGroupName(), node.getHostName().split(" "));		
		if(ret){
			////hostGroupConf.updateConf(hge)//此方法需要再修改。			
			jHCmd.jSchedReconfig();
		}
		//3、调用命令 添加node 到计算节点
		//jHCmd.addHost(node.getHostName());
		jHCmd.addHost(node.getHostName());
	}*/
	/**
	 * 根据页码及页面编号获取指定页面内容
	 * @param pageSize 页面大小
	 * @param pageNow 指定某个页面编号
	 * @deprecated 已采用新的替代具体参见 hostsOfPageN2 方法
	 * ***/
	@Deprecated
	@RequestMapping(value="/hosts/{pageSize}/{pageNow}",method=RequestMethod.GET)
	public ResultData hostsOfPageN(@PathVariable("pageSize")int pageSize,@PathVariable("pageNow")int pageNow ){
		//vNodeService.getNodesByPagesAndPageSize(pageSize, pageNow);
		return success(vNodeService.selectNodesByPagesAndPageSize(pageSize, (pageNow-1)*pageSize));
	}
	@RequestMapping(value="/hosts",method=RequestMethod.GET)
	public ResultData hostsOfPageN2(long pageSize,long offset,String searchText,String sort,String sortOrder ){
		//vNodeService.getNodesByPagesAndPageSize(pageSize, pageNow);
		if(offset<0)
			offset=0;
		if(pageSize<=0)
			pageSize=10;
		return success(vNodeService.selectNodesByPage(new Page<NodeDetail>(pageSize,offset,searchText,sort,sortOrder)));
	}
	/********/
	@RequestMapping(value=("/hosts/{hostName}"),method=RequestMethod.GET)
	public ResultData getHostByName(@PathVariable("hostName")String hostName){
		return null;
	}
	/****
	 * 删除节点：节点删除后，将会从调度系统中消失，通过任何方式都无法检索该节点
	 * 1、从本地数据库删除记录
	 * 2、如果存在，删除hostGroup 中的节点信息。
	 * 3、如果存在擅长hosts.conf中的host信息。
	 * 4、更新配置文件
	 * ***/
	@RequestMapping(value="/hosts/{hostName}",method=RequestMethod.DELETE)
	public ResultData deleteHost(@PathVariable("hostName")String hostName){
		if(hostName==null ||hostName.length()==0)
			return error("操作失败，请求操作的节点名称无效.");
		boolean ret =jHCmd.removeHost(hostName);
		if(ret){//移除成功，仍需继续调整配置文件相关信息
			ret= hostsConf.removeConf(hostName);
			if(ret){
				ret=hostGroupConf.removeConf(hostName);
				if(ret){
					ret =jHCmd.jSchedReconfig();
					if(ret==false){
						return error("节点删除成功，但相关配置重新加载失败，请在控制台执行命令：jadmin schedreconfig，查看具体错误。");
					}
				}
			}else{
				return error("节点删除成功，但相关配置文件修改失败。");
			}
		}else{
			return error("操作失败，为找到指定节点，或节点不存在。");
		}
		if(etcHostsConf.removeConf(hostName)){
			//此处应当重新推送/etc/hosts文件到各个节点
			//this.fanoutConf(etcHostsConf);
		}
		if(0>hostService.updateNodeToInactive(hostName)){
			return error("数据库更新失败。");
		}
		return null;
	}
	/****
	 * 添加节点到调度中心
	 * @param node 要添加的节点信息
	 * @return 返回操作结果，
	 * 包含几步操作
	 * 1、节点的ip 及节点名添加到 /etc/hosts
	 * 2、如果选定group 则需要更新到Hosts.conf 中的HostGroup 
	 * 3、调用调度平台命令 把添加node 到计算节点
	 * 4、如果有GPU 信息则更新GPU 信息到信息库，并保存节点集信息到数据库
	 * ***/
	@RequestMapping(value="/hosts",method=RequestMethod.POST)
 	public ResultData addHostToGroup(Node node){
		if(node.getNodeName().isEmpty())
			return error();
		//1、添加到 /etc/hosts

		etcHostsConf.insertConf(node.getNodeName(), node.getNodeIp(), node.getNodeName()+".innerhost.com");
		//2、更新Hosts.conf 中的HostGroup 
		if(!node.getGroupName().isEmpty()){
			BaseConf bConf =hostGroupConf.findConfByName(node.getGroupName());
			boolean ret=hostGroupConf.updateConf(node.getGroupName(), node.getNodeName().split(" "));		
			if(ret){
				ret=jHCmd.jSchedReconfig();
				if(ret==false){
					//调度平台操作失败，移除更新的内容
					hostGroupConf.removeConf(node.getNodeName());
					//还原已更改的内容
					hostGroupConf.insertConf(bConf);
				}
			}
		}		
		//3、调用命令 添加node 到计算节点
		boolean ret=jHCmd.addHost(node.getNodeName());
		if(ret){			
			//jHCmd.limRegconfig();
			ret=jHCmd.jSchedReconfig();
			if(ret==false){
				return error("节点添加失败。");
			}
		}
		//4、增加GPU信息，到elimGPU，非 conf 文件无需执行控制台更in
		//elimGPU 改为单独添加过程，修改日期2018-11-13，此处node信息未已存在GPU信息，且只包含GPU ID。
		//elimGPU.insertConf(node.getGpuIdentify(), node.getGpuVersion(), node.getGpuDetail());
		//5、node信息添加到数据库
		hostService.insertNode(node);
		//6、广播发送数据到该结点,节点
		//this.p2pNodeProcessLimit(node);
		return success();
	}
	/*****
	 * 节点上下线
	 * @param hostName 待执行上下路线操作的节点名
	 * @param oper 待执行的操作 close :下线; open:上线
	 * @param id 节点的id，用于更新数据库中对应的节点
	 * @return 返回默认成功或失败结果
	 * ****/
	@RequestMapping(value="/hosts/{hostName}/{oper}/{id}",method=RequestMethod.POST)
	public ResultData operNode(@PathVariable("hostName") String hostName,@PathVariable("oper") String oper,@PathVariable("id") int id){
		//1、节点上线或者下线
		boolean ret=jHCmd.hostOper(hostName,oper);
		Log4jInit.logger.info(""+ret);
		if(ret){//节点上下线成功，更新数据库状态信息
			Node node=new Node();
			node.setNodeId(id);
			//Log4jInit.logger.info("   " + oper);

			//Log4jInit.logger.info("   " + oper=="open"?"ok":"closed_Adm");
			node.setStatus("open".equals(oper)?"ok":"closed_Adm");
			hostService.updateNodeById(node);
			return success();
		}
		return error();
	}
	/******
	 * HostGroup 新增，新增的同时写入节点
	 * @param host ，host group 信息
	 * @return 返回操作结果
	 * 1、新增group ,如果group名字已存在的添加失败
	 * 2、新增到配置文件后会自动执行后台刷新，若刷新失败则表明添加失败，并移除已添加的内容。
	 * 3、执行成功则通知各个节点，更新自己的hosts.conf 文件
	 * *****/
	@RequestMapping(value="/hosts/group",method=RequestMethod.POST)
	public ResultData addGroup(HostGroupEntity hostGroup){
		//1、开始向hosts.conf 中写入hostGroup 信息
		boolean result=hostGroupConf.insertConf(hostGroup);
		//2、写入后开始通知调度系统更新配置文件到内存
		if(result){
			result=jHCmd.jSchedReconfig();			
			if(result){//通知执行成功，通知各个节点，更新自己的文件				
				//fanoutConf(hostGroupConf);
				return success();
			}
			//调度平台执行失败。
			hostGroupConf.removeConf(hostGroup.getKey());
		}
		//插入失败，返回错误信息
		return error();
	}
	/******
	 * HostGroup 删除
	 * @param hostGroupName 待删除的HostGroupName
	 * @return 返回操作结果
	 * 1、删除group ,如果group名字不存在则删除失败
	 * 2、删除HostGroup配置文件后会自动执行后台刷新，若刷新失败则表明删除失败，并还原已经删除的内容。
	 * 3、执行成功则通知各个节点，更新自己的hosts.conf 文件
	 * *****/
	@RequestMapping(value="/hosts/group/{hostGroupName}",method=RequestMethod.DELETE)
	public ResultData removeGroup(@PathVariable("hostGroupName")String hostGroupName){
		//1、备份原有的HostGroup 信息
		BaseConf bConf=hostGroupConf.findConfByName(hostGroupName);
		if(bConf==null)
			return error("未找到指定的HostGroupName");
		//2、开始删除HostGroup
		boolean result=hostGroupConf.removeConf(hostGroupName);
		if(result){//删除成功
			result=jHCmd.jSchedReconfig();
			if(result){//通知调度平台刷新成功
				//3、通知各个节点,更新本地conf 文件
				//fanoutConf(hostGroupConf);
				return success();
			}
			//4、调度平台刷新失败,恢复删除的内容
			hostGroupConf.insertConf(bConf);						
		}
		//删除失败，直接返回错误信息
		return error();
	}
	/*************
	 * 根据分组名返回分组中的hosts 信息
	 * @param groupName
	 * @return 返回分组中的hosts
	 * ***************/
	@RequestMapping(value="/hosts/group/{groupName}",method = RequestMethod.GET)
	public ResultData getHostsByGroupName(@PathVariable("groupName")String groupName){
		HostGroupEntity hGE=(HostGroupEntity)hostGroupConf.findConfByName(groupName);
		if(hGE!=null){
			return success(hGE.getHosts());
		}
		return error();
	}
	/*****
	 * 更新Group
	 * @param host
	 * *****/
	@RequestMapping(value="/hosts/group/{groupName}",method = RequestMethod.PUT)
	public ResultData updateHostGroup(HostGroupEntity ge,@PathVariable("groupName")String groupName ){
		if(groupName==null)
			return error("无效的分组名");
		String errMsg="Group 信息异常";
		println(ge.getHostGroupName());
		println(ge.getHosts());
		if(!MyStringUtils.isBlank(ge.getHostGroupName())&& ge.getHosts().length>0){
			//保存旧的HostGroup信息
			BaseConf bConf =hostGroupConf.findConfByName(groupName);
			if(bConf==null)return error("为找到指定Group信息");
			errMsg="移除旧信息失败";
			//删除原有的HostGroup信息
			boolean ret =hostGroupConf.removeConf(bConf);
			if(ret){//写入新的hostGroup信息				
				ret = hostGroupConf.insertConf(ge);
				errMsg="插入新信息失败";
				if(ret){//调度后台更新配置
					ret=jHCmd.jSchedReconfig();
					errMsg="调度执行失败";
					if(ret){//更新成功通知各个节点更新hosts.conf
						//fanoutConf(hostGroupConf);
						return success();
					}
					//调度后台失败，将原来的group写回,此处不需要操作，跳出if之后即可					
				}
				//插入失败，还原原有的HostEntity
				hostGroupConf.insertConf(bConf);				
			}
			//移除失败无需操作，，直接返回擦作失败即可			
		}
		return error(errMsg);
	}
}
